﻿Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics
Imports Runa.UI.Styles
Imports Runa.UI.Metadata
Imports Runa.Resources.ResourceManager

Namespace Global.Runa.UI.Controls

    Public Class Label
        Inherits ContentControl

        Protected WithEvents _TextStyle As TextStyle

        Protected _Progress As Single
        Protected _Text As String = ""
        Protected _TextLineType As Type
        Protected index As Integer
        Protected lst_Text As List(Of String)
        Protected lst_TextLine As List(Of TextLine)
        Protected lst_TextLinesProgress As List(Of Single)

        Public Sub New(ByVal g As Game)
            MyBase.New(g)
            Me._TextLineType = GetType(TextLine)
            Me.lst_Text = New List(Of String)
            Me.lst_TextLine = New List(Of TextLine)
            Me.lst_TextLinesProgress = New List(Of Single)
            Me._TextStyle = New TextStyle(Me.Game)
        End Sub

        Public Sub New(ByVal Parent As UIElementBase)
            MyBase.New("", Parent)
            Me._TextLineType = GetType(TextLine)
            Me.lst_Text = New List(Of String)
            Me.lst_TextLine = New List(Of TextLine)
            Me.lst_TextLinesProgress = New List(Of Single)
            Me._TextStyle = New TextStyle(Me.Game)
        End Sub

        Public Sub New(ByVal Name As String, ByVal TextStyle As TextStyle)
            MyBase.New(Name)
            Me._TextLineType = GetType(TextLine)
            Me.lst_Text = New List(Of String)
            Me.lst_TextLine = New List(Of TextLine)
            Me.lst_TextLinesProgress = New List(Of Single)
            Me._TextStyle = TextStyle
        End Sub

        Public Sub New(ByVal Name As String, ByVal TextStyle As TextStyle, ByVal Parent As UIElementBase)
            MyBase.New(Name, Parent)
            Me._TextLineType = GetType(TextLine)
            Me.lst_Text = New List(Of String)
            Me.lst_TextLine = New List(Of TextLine)
            Me.lst_TextLinesProgress = New List(Of Single)
            Me._TextStyle = TextStyle
        End Sub

        Public Sub Append(ByVal s As String)
            Me.Text += s
        End Sub

        Public Sub AppendLine(ByVal s As String)
            Me.Text += vbCrLf + s
        End Sub

        Public Overrides Sub Draw(ByVal SpriteBatch As SpriteBatch)
            If MyBase.Visible Then
                If MyBase.Background IsNot Nothing And MyBase.Background IsNot Nothing Then
                    If MyBase.Effect IsNot Nothing Then
                        SpriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, Nothing, Nothing, Nothing, MyBase.Effect.Effect)
                    Else
                        SpriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend)
                    End If
                    SpriteBatch.Draw(MyBase.Background.Texture, Me.AbsoluteBounds, Nothing, Color.White * MyBase.Opacity, Me.AbsoluteRotation, MyBase.Orgin, MyBase.SpriteEffect, 0.5!)
                    SpriteBatch.End()
                End If
                For Each line As TextLine In Me.lst_TextLine
                    ' If line.Location.Y + line.Size.Y <= Me.Size.Y Then
                    line.Draw(SpriteBatch)
                    'End If
                Next
                If Me.EndingPoint IsNot Nothing AndAlso Me.EndingTexture IsNot Nothing AndAlso Me.AnimationCompeleted Then
                    If MyBase.Effect IsNot Nothing Then
                        SpriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, Nothing, Nothing, Nothing, MyBase.Effect.Effect)
                    Else
                        SpriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend)
                    End If
                    Dim v = Me._TextStyle.Font.MeasureString("P").Y
                    Dim charRect = New Vector2(v, v)
                    Dim rect As New Rectangle(Me.EndingPoint.Value.Y, Me.EndingPoint.Value.Y, charRect.X, charRect.Y)
                    SpriteBatch.Draw(Me.EndingTexture.Texture, rect, Nothing, Color.White * MyBase.Opacity, Me.AbsoluteRotation, MyBase.Orgin, MyBase.SpriteEffect, 0.5!)
                    SpriteBatch.End()
                End If
                MyBase.Draw(SpriteBatch)
            End If
        End Sub

        Protected Overridable Sub Generate(Optional ByVal isAppend As Boolean = False)
            If Not Me._Text Is Nothing Then
                If isAppend = False Then Me.index = 0
                If Me.Size = Vector2.Zero Then
                    Me.Size = Me._TextStyle.Font.MeasureString(New String(Me._Text.Take(20).ToArray()))
                End If
                Me.lst_Text = Me.GetTextOfEachLine(Me._TextStyle.Font, Me._Text, Me.Size.X)
                Dim oldLineCount = Me.lst_TextLine.Count
                Dim iNewLines As Integer = Me.lst_Text.Count - oldLineCount
                If iNewLines > 0 Then
                    For i As Integer = 0 To iNewLines - 1
                        Dim tl As TextLine = Activator.CreateInstance(Me.TextLineType, New Object() {"", Me, Me._TextStyle})
                        tl.Size = New Vector2(Me.Size.X, tl.Size.Y)
                        Dim h = (From item In Me.lst_TextLine Select item.Size.Y).Sum()
                        'For Each line In Me.lst_TextLine
                        '    h = h + line.Size.Y
                        'Next
                        tl.Location = New Vector2(0.0!, Me.Location.Y + h)
                        Me.lst_TextLine.Add(tl)
                    Next
                Else
                    For i As Integer = 0 To -iNewLines - 1
                        Me.lst_TextLine(Me.lst_TextLine.Count - 1 - i).Text = Nothing
                    Next
                End If
                Me.lst_TextLinesProgress.Clear()
                Dim width = (From item In Me.lst_TextLine Select item.Size.X).Sum()
                'For Each line In Me.lst_TextLine
                '    width = width + line.Size.X
                'Next
                Me.lst_TextLinesProgress.Add(0.0!)
                For i As Integer = 1 To Me.lst_TextLine.Count - 1
                    Me.lst_TextLinesProgress.Add(Me.lst_TextLine(i).Size.X / width + Me.lst_TextLinesProgress(i - 1))
                Next
                Me.lst_TextLinesProgress.Add(1.0!)
                For i As Integer = 0 To Me.lst_Text.Count - 1
                    Me.lst_TextLine(i).Size = New Vector2(Me._Size.X, Me.lst_TextLine(i).Size.Y)
                    Me.lst_TextLine(i).Text = Me.lst_Text(i)
                Next
                If isAppend Then
                    Try
                        Me.Progress = Me.lst_TextLinesProgress(oldLineCount)
                    Catch ex As Exception
                        Me.Progress = 0
                    End Try
                Else
                    Me.Progress = 0
                End If
            End If
        End Sub

        Private Function GetTextLines(ByVal font As SpriteFont, ByVal text As String, ByVal width As Single) As List(Of String)
            Dim result = Me.GetTextOfEachLine(font, text, CDbl(width))
            For i As Integer = 0 To result.Count - 1
                If String.IsNullOrWhiteSpace(result(i)) Then
                    result.Remove(result(i))
                End If
            Next
            Return result
        End Function

        Public Function GetTextOfEachLine() As List(Of String)
            Return Me.GetTextOfEachLine(Me._Text)
        End Function

        Public Function GetTextOfEachLine(ByVal text As String) As List(Of String)
            Try
                Return Me.GetTextOfEachLine(Me._TextStyle.Font, text, Me.Size.X)
            Catch ex As Exception
                Return New List(Of String)
            End Try
        End Function

        Private Function GetTextOfEachLine(ByVal font As SpriteFont, ByVal text As String, ByVal width As Double) As List(Of String)
            Dim result As New List(Of String)
            Dim maxWidth As Integer = 0
            Dim maxLength As Integer = 0
            Dim lines = New String() {text}
            If text.Contains(vbLf) Then
                lines = text.Split(New String() {vbLf}, StringSplitOptions.None)
                maxLength = lines.Max(Function(item) item.Length)
                Dim maxLengthLine = lines.Where(Function(item) item.Length = maxLength).FirstOrDefault()
                maxWidth = font.MeasureString(maxLengthLine).X
            Else
                maxLength = text.Length
                maxWidth = font.MeasureString(text).X
            End If
            For Each line In lines
                Dim linetLength = font.MeasureString(line).X
                If linetLength < width Then
                    result.Add(line)
                Else
                    Dim index As Integer = 0
                    Dim iRows = CInt(linetLength / width + 0.5)
                    Dim rowLength = CInt(line.Length / iRows)
                    For i As Integer = 0 To iRows - 1
                        Dim len As Integer = line.Length - index
                        For x As Integer = 0 To line.Length - index - 1
                            Dim t As String = line.Substring(index, x)
                            If font.MeasureString(t).X >= width Then
                                len = x - 1
                                Exit For
                            End If
                        Next
                        result.Add(line.Substring(index, len))
                        index = index + len
                    Next
                    If index < line.Length Then result.Add(line.Substring(index))
                End If
            Next
            Return result
        End Function

        Private Sub TextStyle_Changed(sender As Object, e As PropertyChangedEventArgs) Handles _TextStyle.PropertyChanged
            For Each line In Me.lst_TextLine
                line.TextStyle = Me.TextStyle
            Next
            Me.Generate()
        End Sub

        Public Overrides Sub UpdateLayout()
            Dim t = Me.Text
            Me.Text = ""
            Me._TextLineType = GetType(TextLine)
            Me.lst_Text = New List(Of String)
            Me.lst_TextLine = New List(Of TextLine)
            Me.lst_TextLinesProgress = New List(Of Single)
            Me.Text = t
        End Sub

        Public ReadOnly Property VisibleLineCount() As Integer
            Get
                Return Me.lst_TextLine.Count
            End Get
        End Property

        Public ReadOnly Property VisibleLines() As List(Of String)
            Get
                Return (From item In Me.lst_TextLine Select item.Text).ToList()
            End Get
        End Property

        <XamlAwareAttribute(IsPlainType:=False, Initializer:=GetType(Texture2DObjectConverter))>
        Public Property EndingTexture() As Texture2DObject = Nothing

        Public ReadOnly Property EndingPoint() As Vector2?
            Get
                Try
                    'Dim maxY = Me.lst_TextLine.Max(Function(item) item.Location.Y)
                    Dim line = Me.lst_TextLine.LastOrDefault(Function(item) item.Location.Y + item.Size.Y <= Me.Size.Y)
                    If line IsNot Nothing Then
                        Dim v = line.DrawClip.Location.ToVector2() _
                            + New Vector2(line.DrawClip.Width, line.DrawClip.Height)
                        Return v + line.Parent.Location
                    Else
                        Return Nothing
                    End If
                Catch ex As Exception
#If Not WINDOWS_PHONE Then
                    Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace.ToString())
#End If
                    Return Nothing
                End Try
            End Get
        End Property

        Public ReadOnly Property ActualBound() As Vector2
            Get
                Dim sum = (From item In Me.lst_TextLine Select item.Size.Y).Sum()
                Return New Vector2(Me.Location.X, Me.Location.Y + sum)
            End Get
        End Property

        Public Overridable Property Progress() As Single
            Get
                Return Me._Progress
            End Get
            Set(ByVal value As Single)
                If Me._Progress <> value Then
                    Me._Progress = value
                    If Me.lst_TextLinesProgress.Count > 0 Then
                        Me.index = 0
                        For i As Integer = 1 To Me.lst_TextLine.Count - 1
                            If Me.lst_TextLinesProgress(i) < Me._Progress Then
                                Me.index = i
                            End If
                        Next
                        Dim s As Single = Me._Progress - Me.lst_TextLinesProgress(Me.index)
                        Dim r As Single = Me.lst_TextLinesProgress(Me.index + 1) - Me.lst_TextLinesProgress(Me.index)
                        Dim p As Single = s / r
                        For i As Integer = 0 To Me.index - 1
                            Me.lst_TextLine(i).Progress = 1.0!
                        Next
                        Me.lst_TextLine(Me.index).Progress = p
                        For i As Integer = Me.index + 1 To Me.lst_TextLine.Count - 1
                            Me.lst_TextLine(i).Progress = 0.0!
                        Next
                    End If
                End If
            End Set
        End Property

        <XamlAwareAttribute(IsPlainType:=False, Initializer:=GetType(Vector2Converter))>
        Public Overrides Property Size() As Vector2
            Get
                Return MyBase.Size
            End Get
            Set(ByVal value As Vector2)
                If (MyBase._Size <> value) Then
                    MyBase.Size = value
                    Me.Generate()
                End If
            End Set
        End Property

        <XamlAwareAttribute(IsPlainType:=False, ElementName:="Text", Initializer:=GetType(RubyStringConverter))>
        Public Overridable Property [Text]() As String
            Get
                Return Me._Text
            End Get
            Set(ByVal value As String)
                If Me._Text <> value Then
                    Dim isAppend = False
                    If value.StartsWith(Me._Text) = False Or String.IsNullOrWhiteSpace(Me._Text) Then
                        Me.lst_Text.Clear()
                        Me.lst_TextLine.Clear()
                        Me.lst_TextLinesProgress.Clear()
                    Else
                        If value.StartsWith(Me._Text) = True Then isAppend = True
                    End If
                    Me._Text = value
                    Try
                        Me.Generate(isAppend)
                    Catch ex As Exception
                        Exit Try
                    End Try
                End If
            End Set
        End Property

        Public Property TextLineType() As Type
            Get
                Return Me._TextLineType
            End Get
            Set(ByVal value As Type)
                If Me._TextLineType IsNot value Then
                    Dim tl As TextLine = Nothing
                    Try
                        tl = TryCast(Activator.CreateInstance(value, New Object() {"", Me, Me._TextStyle}), TextLine)
                    Catch
                        Exit Try
                    End Try
                    If tl IsNot Nothing Then
                        Me._TextLineType = value
                        Me.lst_TextLine.Clear()
                        Me.Generate()
                    End If
                End If
            End Set
        End Property

        Public Overridable Property TextStyle() As TextStyle
            Get
                Return Me._TextStyle
            End Get
            Set(ByVal value As TextStyle)
                If Me._TextStyle IsNot value Then
                    Me._TextStyle = value
                    Me.Generate()
                End If
            End Set
        End Property

    End Class

End Namespace